package com.jt.redis;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class JedisDataSource {
    //方案1:饿汉式 (类加载时创建对象)
//    private static JedisPool jedisPool;
//    static{
//        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
//        config.setMaxTotal(16);//最大连接数
//        config.setMaxIdle(8);//最大空闲连接数
//        config.setMinIdle(4);//最小空闲连接数
//        jedisPool = new JedisPool(config, "192.168.126.129", 6379);
//    }

    //方案2:懒汉式(何时需要何时创建)
    /**
     * Jedis连接池对象
     * volatile 关键字的作用? (通常会配合双重校验锁使用)
     * 1)禁止JVM指令重排序
     * 2)保证线程共享变量可见性(一个线程改了值后,其它线程立刻可见.)
     * 3)但不保证原子性.
     */
    private static volatile JedisPool jedisPool;
    /**
     * 从池中获取一个连接
     * @return
     */
    public /*synchronized*/ static Jedis getConnection(){
        if(jedisPool==null) {
            synchronized (JedisDataSource.class) {//排它锁,独占锁,悲观锁
                if (jedisPool == null) {
                    System.out.println("==create jedis pool==");
                    GenericObjectPoolConfig config = new GenericObjectPoolConfig();
                    config.setMaxTotal(16);//最大连接数
                    config.setMaxIdle(8);//最大空闲连接数
                    config.setMinIdle(4);//最小空闲连接数
                    jedisPool = new JedisPool(config, "192.168.126.129", 6379);
                    //上面这一行的执行逻辑???
                    //1.分配池对象空间
                    //2.属性默认初始化
                    //3.构造方法
                    //4.将对象地址赋值给jedisPool这个变量
                }
            }
        }
        return jedisPool.getResource();
    }

    //通过方法内局部变量的定义,优化系统性能(减少了主内存与线程本地内存的数据交换次数)
    public static Jedis getConnection02(){
        JedisPool pool=jedisPool;
        if(pool==null) {
            synchronized (JedisDataSource.class) {//排它锁,独占锁,悲观锁
                pool=jedisPool;
                if (pool == null) {
                    System.out.println("==create jedis pool==");
                    GenericObjectPoolConfig config = new GenericObjectPoolConfig();
                    config.setMaxTotal(16);//最大连接数
                    config.setMaxIdle(8);//最大空闲连接数
                    config.setMinIdle(4);//最小空闲连接数
                    pool=jedisPool = new JedisPool(config, "192.168.126.129", 6379);
                    //上面这一行的执行逻辑???
                    //1.分配池对象空间
                    //2.属性默认初始化
                    //3.构造方法
                    //4.将对象地址赋值给jedisPool这个变量
                }
            }
        }
        return pool.getResource();
    }
    public static void close(){
        if(jedisPool!=null){
            jedisPool.close();
            jedisPool=null;
        }
    }

    public static void main(String[] args) {
        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                JedisDataSource.getConnection();
            }
        });
        Thread t2=new Thread(new Runnable() {
            @Override
            public void run() {
                JedisDataSource.getConnection();
            }
        });
        Thread t3=new Thread(new Runnable() {
            @Override
            public void run() {
                JedisDataSource.getConnection();
            }
        });
        t1.start();
        t2.start();
        t3.start();
    }
}
